/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package at.ac.tuwien.ewa.g70.api;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;

/**
 *
 * @author Amras
 */
@ManagedBean(name="cardManager")
@SessionScoped
public class CardManager {

    private int rows, cols;
    private int pairs;
    private int foundPairs;
    private long startTime;
    private long endTime;
    private List<List<Card>> cards;
    private List<Card> cards2;
    private int tries;

    private Card firstUncovered, secondUncovered;

    public static enum State {
            START, ONE_UNCOVERED, MISMATCH, END;
    }

    private State state;
    public boolean mismatch;


    public static List<Card> getDefaultCards() {
            String[] cardNames = { "Muse", "", "Radiohead", "", "", "", "Mars", "", "", "", "", "", "", "", "", "", "", "" };

            List<Card> cards = new ArrayList<Card>();
            for (int i = 0; i < cardNames.length; i++) {
                    Card c = new Card();
                    c.setShown(false);
                    c.setImgURL("img/card_images/card" + (i+1) + ".jpg");
                    c.setName(cardNames[i]);

                    cards.add(c);
            }

            return cards;
    }


    public void init(List<Card> images, int rows, int cols) {
            state = State.START;

            cards = new ArrayList<List<Card>>(rows);
            cards2 = new ArrayList<Card>(rows*cols);
            this.rows = rows;
            this.cols = cols;
            int size = rows * cols;
            pairs = size / 2;
            foundPairs = 0;
            tries = 0;

            startTime = System.currentTimeMillis();
            endTime = 0;

            // check the amount of images
            if( images.size() < pairs ) {
                    throw new IllegalArgumentException("Too many cells requested for available images");
            }
            else {
                    images = images.subList(0, pairs);
            }

            // double the images and shuffle it
            for (Card c : new ArrayList<Card>(images)) {
                    images.add(c.clone());
            }
            Collections.shuffle(images);

            // create cards matrix
            Iterator<Card> itFiles = images.iterator();
            while (itFiles.hasNext()) {
                    List<Card> row = new ArrayList<Card>();
                    for (int i = 0; i < cols; i++) {
                            row.add(itFiles.next());
                    }
                    cards.add(row);
            }
            
            itFiles = images.iterator();
            while (itFiles.hasNext()) {
                 cards2.add(itFiles.next());
            }
    }
    
    public void setCards2(List<Card> cards2) {
        this.cards2 = cards2;
    }

    public List<Card> getCards2() {
        return cards2;
    }

    public boolean isMismatch() {
        return mismatch;
    }

    public void setMismatch(boolean mismatch) {
        this.mismatch = mismatch;
    }
    
    public int getRows() {
            return rows;
    }

    public void setRows(int rows) {
            this.rows = rows;
    }

    public int getCols() {
            return cols;
    }

    public void setCols(int cols) {
            this.cols = cols;
    }

    public int getFoundPairs() {
            return foundPairs;
    }

    public int getRemainingPairs() {
            return pairs - foundPairs;
    }

    public long getPlayTime() {
            if(endTime == 0)
                    return System.currentTimeMillis() - startTime;
            else
                    return endTime - startTime;
    }

    public String getPlayTimeString(){
        return Math.round(getPlayTime()/60000)+":"+Math.round((getPlayTime()-(Math.round(getPlayTime()/60000)*60000))/1000);
    }

    public int getTries() {
            return tries;
    }

    public List<List<Card>> getCards() {
            return cards;
    }

    public void setCards(List<List<Card>> cards) {
            this.cards = cards;
    }

    public State getState() {
            return state;
    }

    public Card getFirstUncovered() {
            return firstUncovered;
    }

    public Card getSecondUncovered() {
            return secondUncovered;
    }

    public Card getCard(int i, int j) {
            return cards.get(i).get(j);
    }

    public boolean isShown(int i, int j) {
            return getCard(i,j).isShown();
    }

    public boolean allUncovered() {
            for (List<Card> row : getCards()) {
                    for (Card c : row) {
                            if (!c.isShown()) {
                                    return false;
                            }
                    }
            }
            return true;
    }

    public void uncover(ActionEvent e)   {
        Card card = (Card) e.getComponent().getAttributes().get("Card");
        uncover(card);
        FacesContext.getCurrentInstance().renderResponse();
    }

    public void uncover(Card c) {
        for(int i=0; i<cols; i++)
            for(int j=0; j<rows; j++)
                if(this.getCard(i,j).equals(c))
                    uncover(i,j);
    }
    
    /**
     * Tries to uncover the card at (i,j).
     * @param i row
     * @param j column
     */
    public void uncover(int i, int j) {
            switch (state) {
            case START:
                    mismatch = false;
                    firstUncovered = getCard(i, j);
                    firstUncovered.setShown(true);
                    state = State.ONE_UNCOVERED;
                    break;
            case ONE_UNCOVERED:
                    mismatch = false;
                    secondUncovered = getCard(i, j);
                    secondUncovered.setShown(true);
                    if (secondUncovered != firstUncovered
                                    && secondUncovered.equals2(firstUncovered)) {
                            firstUncovered = null;
                            secondUncovered = null;
                            foundPairs++;
                            if (allUncovered()) {
                                    endTime = System.currentTimeMillis();
                                    state = State.END;
                            } else {
                                    state = State.START;
                            }
                    } else {
                            state = State.MISMATCH;
                            mismatch = true;
                    }
                    tries++;
                    break;
            case MISMATCH:
                    mismatch = false;
                    firstUncovered.setShown(false);
                    secondUncovered.setShown(false);
                    firstUncovered = null;
                    secondUncovered = null;
                    state = State.START;
                    uncover(i,j);
                    break;
            case END:
                    // Nothing to uncover :-)
                    break;
            }
    }
}
